package com.fumin.filter;

import com.fumin.common.ApplicationContextHelper;
import com.fumin.common.JsonData;
import com.fumin.common.RequestHolder;
import com.fumin.model.SysUser;
import com.fumin.service.SysCoreService;
import com.fumin.util.JsonMapper;
import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 自定义权限拦截器
 * @Author xiayuxuanmin
 * @Date 2019/11/21
 * @Description
 */
@Slf4j
public class AclControllerFilter implements Filter {
    //定义全局的需要排除掉的请求url集合(白名单,即这些请求直接放过,不需要检测)
    private static Set<String> exclusionUrlSet = Sets.newConcurrentHashSet();
    //定义无权限访问的url
    private final static String noAuthUrl = "/sys/user/noAuth.page";
    /**
     * 获取白名单(不需要检测的url)
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //这里需要知道需要拦截哪些url,哪些url需要放行,所以需要定义一个白名单出来
        //获取需要排除的url
        String exclusionUrls = filterConfig.getInitParameter("exclusionUrls");
        //移去前后空格,移去结果中的空字符串,例如:'a',,'b'会变为'a','b'
        List<String> exclusionUrlList = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(exclusionUrls);
        exclusionUrlSet = Sets.newConcurrentHashSet(exclusionUrlList);
        //把无权限访问的url添加到白名单中
        exclusionUrlSet.add(noAuthUrl);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String servletPath = request.getServletPath();
        Map parameterMap = request.getParameterMap();
        if(exclusionUrlSet.contains(servletPath)){
            //如果请求在白名单中,那么直接通行
            filterChain.doFilter(servletRequest,servletResponse);
            return;
        }
        SysUser sysUser = RequestHolder.getCurrentUser();
        if(sysUser == null){
            //这里做一个记录,看有多少人来无权限登录,记录下请求路径和请求参数
            log.info("someone visit {},but no login ,parameter:{}",servletPath, JsonMapper.obj2String(parameterMap));
            noAuth(request,response);
            return;
        }
        //因为filter不是被spring管理的,所以需要从application中获取下面的值
        SysCoreService sysCoreService = ApplicationContextHelper.popBean(SysCoreService.class);
        if (!sysCoreService.hasUrlAcl(servletPath)) {
            //如果没有权限访问
            log.info("user:{},visit {},login ,parameter:{}",JsonMapper.obj2String(sysUser),servletPath, JsonMapper.obj2String(parameterMap));
            noAuth(request,response);
            return;
        }
        filterChain.doFilter(servletRequest,servletResponse);
    }

    /**
     * 处理无权限请求,分为两种:
     * 1.JSON数据的请求
     * 2.其他请求
     * @param request
     * @param response
     * @throws IOException
     */
    private void noAuth(HttpServletRequest request,HttpServletResponse response) throws IOException {
        String servletPath = request.getServletPath();
        if (servletPath.endsWith(".json")) {
            //如果请求的是json数据,那么返回json数据
            JsonData jsonData = JsonData.fail("没有访问权限,如需访问,请联系管理员!");
            response.setHeader("Content-Type","application/json");
            response.getWriter().println(JsonMapper.obj2String(jsonData));
            return;
        }else{
            //其他的请求,直接返回无权限页面
            clientRedirect(noAuthUrl,response);
            return;
        }
    }

    /***
     * 无权限访问请求页面的响应填充数据
     * @param url
     * @param response
     * @throws IOException
     */
    private void clientRedirect(String url, HttpServletResponse response) throws IOException{
        response.setHeader("Content-Type", "text/html");
        response.getWriter().print("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
                + "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" + "<head>\n" + "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"/>\n"
                + "<title>跳转中...</title>\n" + "</head>\n" + "<body>\n" + "跳转中，请稍候...\n" + "<script type=\"text/javascript\">//<![CDATA[\n"
                + "window.location.href='" + url + "?ret='+encodeURIComponent(window.location.href);\n" + "//]]></script>\n" + "</body>\n" + "</html>\n");
    }

    @Override
    public void destroy() {

    }
}
